﻿using Infrastructure.Utility.Core.CommonUtility;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Infrastructure.Utility.Core.ZiZhuXueLi
{
    public static class ZiZhuXueLiSignHelper
    {

        /*
        sign= MD5( (userId+固定字符串) )
        示例： sign = MD5(USER2022101901000000000001ZIZHUXUELI)
        固定字符：ZIZHUXUELI
        固定用户标识(管理端相关接口使用)：ADMIN
        var userSign= {
        "sign":sign,
        "userId":"USER2022101901",
        "timestamp":当时的时间戳
        }
        var aesSign= Aes.Encry(userSign);
         */

        #region 生成签名、验证签名

        private const string SignFixTail = "ZIZHUXUELI";

        /// <summary>
        /// 基于userid生成签名
        /// </summary>
        /// <param name="userid"></param>
        /// <returns></returns>
        public static string GenerateSign(string userid)
        {
            //设置userid默认值
            if (string.IsNullOrWhiteSpace(userid))
            {
                userid = "ADMIN";
            }

            //对userid进行加密
            var sign = Md5Encrypt(userid + SignFixTail);

            //生成签名对象
            var userSign = new UserSign
            {
                Sign = sign,
                UserId = userid,
                TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            };

            //签名对象序列化后，AES加密
            var userSignStr = JsonSerializer.Serialize(userSign);
            var userSignAes = AesEncrypt(userSignStr);

            //返回结果
            return userSignAes;
        }


        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="userSignAes"></param>
        /// <param name="userId"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public static bool VerifySign(string userSignAes, string userId, out string msg)
        {
            try
            {
                msg = "签名验证成功！";
                //AES解密签名、反序列化签名对象
                var userSignStr = AesDecrypt(userSignAes);
                if (string.IsNullOrWhiteSpace(userSignStr))
                {
                    msg = "签名为空，验证失败！";
                    return false;
                }
                var userSign = JsonSerializer.Deserialize<UserSign>(userSignStr);

                if (userSign == null)
                {
                    msg = "签名为空，验证失败！";
                    return false;
                }

                if (string.IsNullOrWhiteSpace(userSign.Sign))
                {
                    msg = "无签名密文，验证失败！";
                    return false;
                }

                if (string.IsNullOrWhiteSpace(userSign.UserId))
                {
                    msg = "无用户标识，验证失败！";
                    return false;
                }

                if (string.IsNullOrWhiteSpace(userSign.TimeStamp) || !DateTime.TryParse(userSign.TimeStamp, out DateTime timestamp))
                {
                    msg = "签名无时间戳，验证失败！";
                    return false;
                }

                if (timestamp < DateTime.Now.AddMinutes(-10))
                {
                    msg = @$"签名已过期，验证失败！timestamp:{timestamp.ToStringD19()},timeNow:{DateTime.Now.ToStringD19()}";
                    return false;
                }

                var sign = Md5Encrypt(userSign.UserId + SignFixTail);
                if (sign != userSign.Sign)
                {
                    msg = "签名比对失败，验证失败！";
                    return false;
                }

                if (!string.IsNullOrWhiteSpace(userId) && userId != userSign.UserId)
                {
                    msg = "签名不是指定的用户，验证失败！";
                    return false;
                }

                msg = userSign.UserId;

                return true;
            }
            catch (Exception)
            {
                msg = "非法的签名，验证失败！";
                return false;
            }
        }
        #endregion


        #region AES加密和解密
        private const string Key = "@!#123457892512654*-/78514235=&1";
        private const string Iv = "1234578960785462";
        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="input">输入</param>
        /// <returns></returns>
        public static string AesEncrypt(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return string.Empty;
            }

            var encryptKey = Encoding.UTF8.GetBytes(Key);
            var iv = Encoding.UTF8.GetBytes(Iv); //偏移量,最小为16
            using (var aesAlg = Aes.Create()) //默认CBC
            {
                using (var encryptor = aesAlg.CreateEncryptor(encryptKey, iv))
                {
                    using (var msEncrypt = new MemoryStream())
                    {
                        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor,
                            CryptoStreamMode.Write))
                        using (var swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(input);
                        }
                        var decryptedContent = msEncrypt.ToArray();
                        return Convert.ToBase64String(decryptedContent);
                    }
                }
            }
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="input">输入</param>
        /// <returns></returns>
        public static string AesDecrypt(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return string.Empty;
            }

            try
            {
                var fullCipher = Convert.FromBase64String(input);
                var iv = Encoding.UTF8.GetBytes(Iv);
                var key = Encoding.UTF8.GetBytes(Key);
                using (var aesAlg = Aes.Create())
                {
                    using (var decryptor = aesAlg.CreateDecryptor(key, iv))
                    {
                        string result;
                        using (var msDecrypt = new MemoryStream(fullCipher))
                        {
                            using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                            {
                                using (var srDecrypt = new StreamReader(csDecrypt))
                                {
                                    result = srDecrypt.ReadToEnd();
                                }
                            }
                        }
                        return result;
                    }
                }
            }
            catch (Exception e)
            {
                return input;
            }

        }
        #endregion

        #region MD5加密和验证
        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string Md5Encrypt(string str)
        {
            if (string.IsNullOrWhiteSpace(str))
            {
                return string.Empty;
            }

            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] bytes = Encoding.UTF8.GetBytes(str);
            string result = BitConverter.ToString(md5.ComputeHash(bytes));
            return result.Replace("-", "");
        }

        /// <summary>
        /// MD5验证
        /// </summary>
        /// <param name="str"></param>
        /// <param name="hash"></param>
        /// <returns></returns>
        public static bool Md5Verify(string str, string hash)
        {
            string hashOfInput = Md5Encrypt(str);
            if (hashOfInput.CompareTo(hash) == 0)
                return true;
            else
                return false;
        }
        #endregion
    }


    public class UserSign
    {
        public string Sign { get; set; }

        public string UserId { get; set; }

        public string TimeStamp { get; set; }
    }
}
